#include "EpollTool.h"

/*���ļ�����������Ϊ������*/
int setnonblocking(int fd)
{
    int old_option = fcntl(fd, F_GETFL);
    int new_option = old_option | O_NONBLOCK;
    fcntl(fd, F_SETFL, new_option);
    return old_option;
}

void add_event(int epollfd, int listenfd, int state)
{
    struct epoll_event ev;
    ev.data.fd = listenfd;
    ev.events = EPOLLIN;
    if(state)
        ev.events |= EPOLLET;
    
    epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev);
    setnonblocking(listenfd);
}

int EpollTool::Init(int listenfd)
{
    int epollfd = 0;

    epollfd = epoll_create(FDSIZE);
    if(epollfd < 0)
    {
        perror("epoll_create");
        return -1;
    }
    add_event(epollfd, listenfd, LT_MODE);
    return epollfd;
}

int EpollTool::WaitHandle(int epollfd, struct epoll_event * events, int size, int timeout)
{
    return epoll_wait(epollfd, events, size, timeout);
}

void EpollTool::AcceptHandler(int listenfd, int epollfd, int enable_et, Event *event)
{
    struct sockaddr_in client_address;
    socklen_t client_addrlength = sizeof(client_address);
    int clientfd = accept(listenfd, (struct sockaddr* )&client_address, &client_addrlength);
    if(clientfd == -1)
    {
        perror("accept");
    }else{
        add_event(epollfd, clientfd, enable_et);
        /* accept�ϲ�ҵ��ص����� */
        event->AcceptHandle(clientfd); 
    }
}

void EpollTool::LtHandle(struct epoll_event * events, int number, int epollfd, int listenfd, Event *event)
{
    int idx = 0;
    int sockfd = 0;
    
    for(idx = 0; idx < number; idx++)
    {
        sockfd = events[idx].data.fd;
        if(sockfd == listenfd)
        {
            AcceptHandler(listenfd, epollfd, LT_MODE, event);
        }else if(events[idx].events & EPOLLIN){
            
            /*ֻҪsocket�������еĻ���δ�������ݣ��˴�����ܴ���*/
            int ret = 0;
            ret = event->RecvMessageHandle(sockfd);
            if(ret <= 0){
                close(sockfd);
                continue;
            }
        }else{
            printf("Something else happen !!!\n");
        }
    }

}

void EpollTool::EtHandle(struct epoll_event * events, int number, int epollfd, int listenfd, Event *event)
{
    int idx=0, ret = 0;
    int sockfd = 0;

    for(idx = 0; idx < number; idx++)
    {
        sockfd = events[idx].data.fd;
 
        if(sockfd == listenfd)
        {
            //AcceptHandler(listenfd, epollfd, ET_MODE);
        }else if(events[idx].events & EPOLLIN)
        {
            /*��δ��벻�ᱻ�ظ���������������ѭ����ȡ���ݣ���ȷ����socket������������ȫ����ȡ*/
            printf("Event trigger once !!!\n");
            while(1)
            {
                ret = event->RecvMessageHandle(sockfd);
                if(ret < 0)
                {
                    /*���ڷ�����IO��������¼�������ʶ�����Ѿ�ȫ����ȡ��ϡ��˺�epoll�����ٴδ���sockfd�ϵ�sockfd��EPOLLIN�¼�����������һ�ζ�����*/
                    if((errno == EAGAIN) || (errno == EWOULDBLOCK)){
                        printf("read later\n");
                        break;
                    }
                    close(sockfd);
                    break;
                }else if(ret == 0){
                    close(sockfd);
                }
            }
        }else{
            printf("something else happen\n");
        }
    }
}

